frontend/pages/e/[uuid].tsx (view raw)
1import {useState, useReducer, useEffect} from 'react';
2import Box from '@material-ui/core/Box';
3import {makeStyles} from '@material-ui/core/styles';
4import {useTranslation} from 'react-i18next';
5import {initializeApollo} from '../../lib/apolloClient';
6import useToastStore from '../../stores/useToastStore';
7import useEventStore from '../../stores/useEventStore';
8import Layout from '../../layouts/Default';
9import AddToMyEventDialog from '../../containers/AddToMyEventDialog';
10import TravelColumns from '../../containers/TravelColumns';
11import NewTravelDialog from '../../containers/NewTravelDialog';
12import VehicleChoiceDialog from '../../containers/VehicleChoiceDialog';
13import WelcomeDialog from '../../containers/WelcomeDialog';
14import EventBar from '../../containers/EventBar';
15import Loading from '../../containers/Loading';
16import OnBoardingTour from '../../containers/OnBoardingTour';
17import {
18 useUpdateEventMutation,
19 Event as EventType,
20 useEventByUuidQuery,
21 EventByUuidDocument,
22 EditEventInput,
23} from '../../generated/graphql';
24import ErrorPage from '../_error';
25import AddTravel from '../../containers/TravelColumns/AddTravel';
26import useProfile from '../../hooks/useProfile';
27
28const POLL_INTERVAL = 10000;
29
30interface Props {
31 event: EventType;
32 eventUUID: string;
33}
34
35const EventPage = props => {
36 const {t} = useTranslation();
37 const {event} = props;
38 if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
39 return <Event {...props} />;
40};
41
42const Event = (props: Props) => {
43 const {eventUUID} = props;
44 const classes = useStyles();
45 const {t} = useTranslation();
46 const {user} = useProfile();
47 const addToast = useToastStore(s => s.addToast);
48 const setEvent = useEventStore(s => s.setEvent);
49 const eventUpdate = useEventStore(s => s.event);
50 const setIsEditing = useEventStore(s => s.setIsEditing);
51 const [updateEvent] = useUpdateEventMutation();
52 const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
53 const [openNewTravel, toggleNewTravel] = useReducer(i => !i, false);
54 const [openVehicleChoice, toggleVehicleChoice] = useReducer(i => !i, false);
55 const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
56 pollInterval: POLL_INTERVAL,
57 variables: {uuid: eventUUID},
58 });
59
60 useEffect(() => {
61 if (event) setEvent(event as EventType);
62 }, [event]);
63
64 const onSave = async e => {
65 try {
66 const {uuid, ...data} = eventUpdate;
67 const {id, __typename, travels, users, waitingList, ...input} = data;
68 await updateEvent({
69 variables: {uuid, eventUpdate: input as EditEventInput},
70 refetchQueries: ['eventByUUID'],
71 });
72 setIsEditing(false);
73 } catch (error) {
74 console.error(error);
75 addToast(t('event.errors.cant_update'));
76 }
77 };
78
79 const onShare = async () => {
80 if (!event) return null;
81 // If navigator share capability
82 if (!!navigator.share)
83 return await navigator.share({
84 title: `Caroster ${event.name}`,
85 url: `${window.location.href}`,
86 });
87 // Else copy URL in clipboard
88 else if (!!navigator.clipboard) {
89 await navigator.clipboard.writeText(window.location.href);
90 addToast(t('event.actions.copied'));
91 return true;
92 }
93 };
94
95 if (!event) return <Loading />;
96
97 return (
98 <Layout
99 pageTitle={t('event.title', {title: event.name})}
100 menuTitle={t('event.title', {title: event.name})}
101 displayMenu={false}
102 >
103 <EventBar
104 event={event}
105 onAdd={setIsAddToMyEvent}
106 onSave={onSave}
107 onShare={onShare}
108 />
109 <TravelColumns toggle={toggleVehicleChoice} />
110 <Box className={classes.bottomRight}>
111 <AddTravel toggle={user ? toggleVehicleChoice : toggleNewTravel} />
112 </Box>
113 <NewTravelDialog open={openNewTravel} toggle={toggleNewTravel} />
114 <VehicleChoiceDialog
115 open={openVehicleChoice}
116 toggle={toggleVehicleChoice}
117 toggleNewTravel={toggleNewTravel}
118 />
119 <AddToMyEventDialog
120 event={event}
121 open={isAddToMyEvent}
122 onClose={() => setIsAddToMyEvent(false)}
123 />
124 <WelcomeDialog />
125 <OnBoardingTour />
126 </Layout>
127 );
128};
129
130export async function getServerSideProps(ctx) {
131 const {uuid} = ctx.query;
132 const apolloClient = initializeApollo();
133 const {data = {}} = await apolloClient.query({
134 query: EventByUuidDocument,
135 variables: {uuid},
136 });
137 const {eventByUUID: event} = data;
138 const {host = ''} = ctx.req.headers;
139
140 return {
141 props: {
142 event,
143 eventUUID: uuid,
144 metas: {
145 title: event?.name || '',
146 url: `https://${host}${ctx.resolvedUrl}`,
147 },
148 },
149 };
150}
151
152const useStyles = makeStyles(theme => ({
153 bottomRight: {
154 position: 'absolute',
155 bottom: theme.spacing(1),
156 right: theme.spacing(6),
157 width: 200,
158 },
159}));
160
161export default EventPage;